package com.file.parser;


import com.file.bo.ResponseData;
import com.file.bo.mail.ZYB;
import com.file.bo.mail.ZYBTran;
import com.file.constant.ErrorCode;
import com.file.util.JsonUtils;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.apache.pdfbox.pdmodel.PDDocument;
import technology.tabula.*;
import technology.tabula.detectors.SpreadsheetDetectionAlgorithm;
import technology.tabula.extractors.SpreadsheetExtractionAlgorithm;

import java.io.File;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

@Slf4j
public class ZYBPdfParser extends BaseDecryptPdfParser {

    public ResponseData<String> parseZybPdfToJson(String daId, String filePath, String pdfPwd) {
        log.info("parseZybPdfToJson started, daId:{}", daId);
        String json = null;

        try {
            ZYB zyb = parseZyb(filePath, pdfPwd);
            json = JsonUtils.convertObjectToJson(zyb);
        } catch (Exception e) {
            log.error("OnError|{}||{}|{}|{}|{}", ErrorCode.FILE_PARSE_EXCEPTION.getCode(), daId, "", "", "parseZybPdfToJson failed", e);
            return new ResponseData<>(null, ErrorCode.FILE_PARSE_EXCEPTION.getCode(), ErrorCode.FILE_PARSE_EXCEPTION.getMsg());
        }

        log.info("parseZybPdfToJson completed, daId:{}", daId);
        return new ResponseData<>(json, ErrorCode.SUCCESS.getCode(), ErrorCode.SUCCESS.getMsg());
    }

    private ZYB parseZyb(String filePath, String pdfPwd) {
        ZYB zyb = parseZybHeader(filePath, pdfPwd);
        List<List<String>> rowList = parseFileToRowList(filePath, pdfPwd);
        parseListToBO(rowList, zyb);

        return zyb;
    }

    private void parseListToBO(List<List<String>> rowList, ZYB zyb) {
        List<ZYBTran> zybTrans = new ArrayList<>();

        for (int i = 0; i < rowList.size(); i++) {
            List<String> cellList = rowList.get(i);
            if (StringUtils.equalsAny(cellList.get(0), "账户交易流水", "起始日期", "账户名称", "交易日期")) {
                continue;
            }

            if (cellList.size() == 11) {
                ZYBTran zybTran = new ZYBTran();
                zybTran.setTranDate(cellList.get(0));
                zybTran.setTranTime(cellList.get(1));
                zybTran.setAmount(cellList.get(2));
                zybTran.setRevenueExpenditureStatus(cellList.get(3));
                zybTran.setBalance(cellList.get(4));
                zybTran.setCounterPartyBankName(cellList.get(5));
                zybTran.setCounterPartyAccountName(cellList.get(6));
                zybTran.setCounterPartyAccountNumber(cellList.get(7));
                zybTran.setTradeChannel(cellList.get(8));
                zybTran.setTradeType(cellList.get(9));
                zybTran.setCurrency(cellList.get(10));
                zybTrans.add(zybTran);
            } else if (cellList.size() == 8) {
                ZYBTran zybTran = new ZYBTran();
                zybTran.setTranDate(cellList.get(0));
                zybTran.setTranTime(cellList.get(1));
                zybTran.setAmount(cellList.get(2));
                zybTran.setRevenueExpenditureStatus(cellList.get(3));
                zybTran.setBalance(cellList.get(4));
                zybTran.setTradeChannel(cellList.get(5));
                zybTran.setTradeType(cellList.get(6));
                zybTran.setCurrency(cellList.get(7));
                zybTrans.add(zybTran);
            }
        }

        zyb.setZybTrans(zybTrans);
    }

    private List<List<String>> parseFileToRowList(String filePath, String pdfPwd) {
        // 1. 读取文件
        File pdf = new File(filePath);

        //页面所有table的记录，每一个元素代表下面一条记录cellList
        List<List<String>> rowList = new ArrayList<>();

        // 2. pdfbox读取PDDocument
        try (PDDocument pdfDocument = PDDocument.load(pdf, pdfPwd)) {
            // 3. tabula新建ObjectExtractor和NurminenDetectionAlgorithm，同时准备接收表格Rectangle的结构
            ObjectExtractor objectExtractor = new ObjectExtractor(pdfDocument);
            SpreadsheetDetectionAlgorithm detectionAlgorithm = new SpreadsheetDetectionAlgorithm();
            Map<Integer, List<Rectangle>> pageNumber2RectangleListMap = new HashMap<>();//key为页的序号， value为对应的Rectangle的list

            // 4. 获取每页的PageIterator
            PageIterator pageIterator = objectExtractor.extract();

            // 5. 解析每页的Rectangle
            // 如果单页pdf中有多个Rectangle，则解析出来的List<Rectangle>会有多个对象
            while (pageIterator.hasNext()) {
                Page page = pageIterator.next();
                List<Rectangle> rectangleList = detectionAlgorithm.detect(page);
                if (rectangleList.size() > 0) {
                    pageNumber2RectangleListMap.put(page.getPageNumber(), rectangleList);
                }
            }

            // 6.通过table位置获取表格具体内容
            SpreadsheetExtractionAlgorithm extractionAlgorithm = new SpreadsheetExtractionAlgorithm();

            // 如果单页pdf中有多个表格，则解析出来的List<Rectangle>会有多个对象
            for (Map.Entry<Integer, List<Rectangle>> entry : pageNumber2RectangleListMap.entrySet()) {
                Page page = objectExtractor.extract(entry.getKey());
                Rectangle rectangle = null;

                List<Rectangle> rectangleList = entry.getValue();
                for (Rectangle r : rectangleList) {
                    double rectangleHeight = r.getHeight();
                    if (Double.compare(rectangleHeight, 0) > 0) {
                        rectangle = r;
                        break;
                    }
                }
                if (rectangle == null) {
                    throw new RuntimeException("rectangle is null.");
                }

                if (entry.getKey() > 1) {
                    rectangle.setTop(rectangle.getTop());
                }
//                rectangle.setBottom(rectangle.getBottom() + 5);
                Page area = page.getArea(rectangle);

                // 如果每页有多个表格，解析每一个table
                List<Table> tableList = extractionAlgorithm.extract(area);
                for (Table table : tableList) {
                    for (int i = 0; i < table.getRowCount(); i++) {
                        List<String> cellList = new ArrayList<>();//一条记录，每个单元格占一个元素
                        for (int j = 0; j < table.getColCount(); j++) {
                            cellList.add(table.getCell(i, j).getText(false));
                        }
                        rowList.add(cellList);
                    }
                }
            }
        } catch (Exception e) {
            throw new RuntimeException(e.getMessage());
        }

        return rowList;
    }

    private ZYB parseZybHeader(String filePath, String pdfPwd) {
        ZYB zyb = new ZYB();
        String pdfText = parsePdfHeaderText(filePath, pdfPwd);

        String startDate = pdfText.substring(pdfText.indexOf("账户交易流水起始日期") + 10, pdfText.indexOf("结束日期")).trim();
        String endDate = pdfText.substring(pdfText.indexOf("结束日期") + 4, pdfText.indexOf("收入合计")).trim();
        String applyDateTime = pdfText.substring(pdfText.indexOf("申请时间") + 4, pdfText.indexOf("账户名称")).trim();
        String accountName = pdfText.substring(pdfText.indexOf("账户名称") + 4, pdfText.indexOf("账号")).trim();
        String accountNumber = pdfText.substring(pdfText.indexOf("账号") + 2, pdfText.indexOf("支出合计")).trim();
        String verificationCode = pdfText.substring(pdfText.indexOf("验证码") + 4, pdfText.indexOf("交易日期")).trim();

        zyb.setStartDate(startDate);
        zyb.setEndDate(endDate);
        zyb.setApplyDateTime(applyDateTime);
        zyb.setAccountName(accountName);
        zyb.setAccountNumber(accountNumber);
        zyb.setVerificationCode(verificationCode);

        return zyb;
    }

    public static void main(String[] args) {
        ZYBPdfParser zybPdfParser = new ZYBPdfParser();
        ResponseData<String> responseData = zybPdfParser.parseZybPdfToJson("", "D:\\data\\file\\ZYB\\多页全字段-027058.pdf", "027058");
        log.info(responseData.getData());
    }

}
